// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TaskbarButtonsPackage.cs" company="Roman '4ux-nbIx' Novitsky">
//   Copyright (c) Roman '4ux-nbIx' Novitsky 2010
// </copyright>
// <summary>
//   This is the class that implements the package exposed by this assembly.
//   The minimum requirement for a class to be considered a valid package for Visual Studio
//   is to implement the IVsPackage interface and register itself with the shell.
//   This package uses the helper classes defined inside the Managed Package Framework (MPF)
//   to do it: it derives from the Package class that provides the implementation of the
//   IVsPackage interface and uses the registration attributes defined in the framework to
//   register itself and its components with the shell.
// </summary>
// --------------------------------------------------------------------------------------------------------------------


namespace TaskbarButtons
{
  #region Namespace Imports

  using System;
  using System.Collections.Generic;
  using System.Diagnostics.CodeAnalysis;
  using System.Linq;
  using System.Runtime.InteropServices;
  using System.Threading;

  using CSLib.Net.Annotations;

  using EnvDTE;

  using Microsoft.VisualStudio.Shell;
  using Microsoft.WindowsAPICodePack.Taskbar;

  #endregion


  /// <summary>
  /// Describes and manipulates the taskbar buttons package.
  /// </summary>
  [PackageRegistration(UseManagedResourcesOnly = true)]
  [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
  [ProvideOptionPageAttribute(typeof(OptionsPage), "Environment", "Taskbar Buttons", 101, 107, true)]
  [ProvideProfileAttribute(typeof(OptionsPage), "Environment", "Taskbar Buttons", 101, 106, true, 
    DescriptionResourceID = 101)]
  [Guid(GuidList.TaskbarButtonsPkgString)]
  [ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")]
  [ProvideAutoLoad("{adfc4e64-0397-11d1-9f4e-00a0c911004f}")]
  [UsedImplicitly]
  public sealed class TaskbarButtonsPackage : Package
  {
    #region Constants and Fields

    private readonly object _syncRoot = new object();


    private readonly TaskbarManager _taskbarManager;
    private readonly List<ThumbnailToolbarButton> _toolbarButtons = new List<ThumbnailToolbarButton>();
    private DTE _applicationObject;
    private IList<TaskbarButton> _buttons;
    private bool _buttonsCreated;
    private Timer _timer;

    #endregion


    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="TaskbarButtonsPackage"/> class.
    /// </summary>
    public TaskbarButtonsPackage()
    {
      _taskbarManager = TaskbarManager.Instance;

      Instance = this;
    }

    #endregion


    #region Properties

    /// <summary>
    /// Gets the instance.
    /// </summary>
    /// <value>
    /// The instance.
    /// </value>
    public static TaskbarButtonsPackage Instance
    {
      get;
      private set;
    }

    [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Don't care.")]
    private Window MainWindow
    {
      get
      {
        try
        {
          return _applicationObject.MainWindow;
        }
        catch
        {
          return null;
        }
      }
    }

    #endregion


    #region Public Methods

    /// <summary>
    /// Sets the buttons.
    /// </summary>
    /// <param name="taskbarButtons">
    /// The taskbar buttons.
    /// </param>
    public void SetButtons(IEnumerable<TaskbarButton> taskbarButtons)
    {
      lock (_syncRoot)
      {
        DetachButtons();

        _buttons = taskbarButtons.ToList();
      }
    }

    #endregion


    #region Methods

    /// <summary>
    /// Initializes the taskbar buttons package.
    /// </summary>
    protected override void Initialize()
    {
      base.Initialize();

      _applicationObject = GetService(typeof(DTE)) as DTE;

      if (_applicationObject == null)
      {
        return;
      }

      _timer = new Timer(o => UpdateButtons());
      StartTimer();

      UpdateButtons();
    }


    private void DetachButtons()
    {
      if (_buttons == null)
      {
        return;
      }

      foreach (TaskbarButton button in _buttons)
      {
        button.ToolBarButton = null;
      }
    }


    [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Don't care.")]
    private IList<TaskbarButton> LoadButtonsConfiguration()
    {
      try
      {
        return ButtonsConfiguration.Deserialize(this, _applicationObject).TaskbarButtons;
      }
      catch
      {
        return ButtonsConfiguration.GetDefaultButtonsList(_applicationObject).TaskbarButtons;
      }
    }


    private void StartTimer()
    {
      var period = TimeSpan.FromSeconds(2);

      _timer.Change(period, period);
    }


    private void StopTimer()
    {
      _timer.Change(Timeout.Infinite, Timeout.Infinite);
    }


    /// <summary>
    /// Updates the buttons.
    /// </summary>
    private void UpdateButtons()
    {
      lock (_syncRoot)
      {
        StopTimer();

        if (Zombied)
        {
          return;
        }

        if (MainWindow != null)
        {
          if (!_buttonsCreated)
          {
            CreateTaskbarButtons();
          }

          DetachButtons();

          AttachButtons();
        }

        StartTimer();
      }
    }


    private void AttachButtons()
    {
      int buttonIndex = 0;

      foreach (ThumbnailToolbarButton toolbarButton in _toolbarButtons)
      {
        if (buttonIndex < _buttons.Count)
        {
          int index = buttonIndex;
          var button = _buttons.Where(b => _buttons.IndexOf(b) >= index && b.IsVisible).FirstOrDefault();

          if (button != null)
          {
            button.ToolBarButton = toolbarButton;
            buttonIndex = _buttons.IndexOf(button) + 1;

            continue;
          }
        }

        toolbarButton.Visible = false;
      }
    }


    [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
      Justification = "Don't care.")]
    private void CreateTaskbarButtons()
    {
      if (_buttonsCreated)
      {
        return;
      }

      for (int i = 0; i < 7; i++)
      {
        var button = new ThumbnailToolbarButton(Resources.Gear, string.Empty) { Visible = false };
        _toolbarButtons.Add(button);
      }

      _taskbarManager.ThumbnailToolbars.AddButtons((IntPtr)MainWindow.HWnd, _toolbarButtons.ToArray());

      _buttons = LoadButtonsConfiguration();

      _buttonsCreated = true;
    }

    #endregion
  }
}